home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / ddj0492.zip / DFLT11.ZIP / TEXTBOX.C < prev    next >
Text File  |  1992-01-27  |  28KB  |  888 lines

  1. /* ------------- textbox.c ------------ */
  2.  
  3. #include "dflat.h"
  4.  
  5. static void ComputeWindowTop(WINDOW);
  6. static void ComputeWindowLeft(WINDOW);
  7. static int ComputeVScrollBox(WINDOW);
  8. static int ComputeHScrollBox(WINDOW);
  9. static void MoveScrollBox(WINDOW, int);
  10. static char *GetTextLine(WINDOW, int);
  11.  
  12. BOOL VSliding;
  13. BOOL HSliding;
  14.  
  15. /* ------------ ADDTEXT Message -------------- */
  16. static BOOL AddTextMsg(WINDOW wnd, char *txt)
  17. {
  18.     /* --- append text to the textbox's buffer --- */
  19.     unsigned adln = strlen(txt);
  20.     if (adln > (unsigned)0xfff0)
  21.         return FALSE;
  22.     if (wnd->text != NULL)    {
  23.         /* ---- appending to existing text ---- */
  24.         unsigned txln = strlen(wnd->text);
  25.         if ((long)txln+adln > (unsigned) 0xfff0)
  26.             return FALSE;
  27.         if (txln+adln > wnd->textlen)    {
  28.             wnd->text = realloc(wnd->text, txln+adln+3);
  29.             wnd->textlen = txln+adln+1;
  30.         }
  31.     }
  32.     else    {
  33.         /* ------ 1st text appended ------ */
  34.         wnd->text = calloc(1, adln+3);
  35.         wnd->textlen = adln+1;
  36.     }
  37.     if (wnd->text != NULL)    {
  38.         /* ---- append the text ---- */
  39.         strcat(wnd->text, txt);
  40.         strcat(wnd->text, "\n");
  41.         BuildTextPointers(wnd);
  42.         return TRUE;
  43.     }
  44.     return FALSE;
  45. }
  46.  
  47. /* ------------ DELETETEXT Message -------------- */
  48. static void DeleteTextMsg(WINDOW wnd, int lno)
  49. {
  50.     char *cp1 = TextLine(wnd, lno);
  51.     --wnd->wlines;
  52.     if (lno == wnd->wlines)
  53.         *cp1 = '\0';
  54.     else     {
  55.         char *cp2 = TextLine(wnd, lno+1);
  56.         memmove(cp1, cp2, strlen(cp2)+1);
  57.     }
  58.     BuildTextPointers(wnd);
  59. }
  60.  
  61. /* ------------ INSERTTEXT Message -------------- */
  62. static void InsertTextMsg(WINDOW wnd, char *txt, int lno)
  63. {
  64.     if (AddTextMsg(wnd, txt))    {
  65.         char *cp1 = TextLine(wnd, lno+1);
  66.         char *cp2 = TextLine(wnd, lno);
  67.         memmove(cp1, cp2, strlen(cp2)+1);
  68.         strcpy(cp2, txt);
  69.         BuildTextPointers(wnd);
  70.     }
  71. }
  72.  
  73. /* ------------ SETTEXT Message -------------- */
  74. static BOOL SetTextMsg(WINDOW wnd, char *txt)
  75. {
  76.     /* -- assign new text value to textbox buffer -- */
  77.     unsigned int len = strlen(txt)+1;
  78.     SendMessage(wnd, CLEARTEXT, 0, 0);
  79.     wnd->textlen = len;
  80.     if ((wnd->text=realloc(wnd->text, len+1)) == NULL)
  81.         return FALSE;
  82.     wnd->text[len] = '\0';
  83.     strcpy(wnd->text, txt);
  84.     BuildTextPointers(wnd);
  85.     wnd->wtop = wnd->wleft = 0;
  86.     return TRUE;
  87. }
  88.  
  89. /* ------------ CLEARTEXT Message -------------- */
  90. static void ClearTextMsg(WINDOW wnd)
  91. {
  92.     /* ----- clear text from textbox ----- */
  93.     if (wnd->text != NULL)
  94.         free(wnd->text);
  95.     wnd->text = NULL;
  96.     wnd->textlen = 0;
  97.     wnd->wlines = 0;
  98.     wnd->textwidth = 0;
  99.     wnd->wtop = wnd->wleft = 0;
  100.     ClearTextBlock(wnd);
  101.     ClearTextPointers(wnd);
  102. }
  103.  
  104. /* ------------ KEYBOARD Message -------------- */
  105. static int KeyboardMsg(WINDOW wnd, PARAM p1)
  106. {
  107.     switch ((int) p1)    {
  108.         case UP:
  109.             return SendMessage(wnd,SCROLL,FALSE,0);
  110.         case DN:
  111.             return SendMessage(wnd,SCROLL,TRUE,0);
  112.         case FWD:
  113.             return SendMessage(wnd,HORIZSCROLL,TRUE,0);
  114.         case BS:
  115.             return SendMessage(wnd,HORIZSCROLL,FALSE,0);
  116.         case PGUP:
  117.             return SendMessage(wnd,SCROLLPAGE,FALSE,0);
  118.         case PGDN:
  119.             return SendMessage(wnd,SCROLLPAGE,TRUE,0);
  120.         case CTRL_PGUP:
  121.             return SendMessage(wnd,HORIZPAGE,FALSE,0);
  122.         case CTRL_PGDN:
  123.             return SendMessage(wnd,HORIZPAGE,TRUE,0);
  124.         case HOME:
  125.             return SendMessage(wnd,SCROLLDOC,TRUE,0);
  126.         case END:
  127.             return SendMessage(wnd,SCROLLDOC,FALSE,0);
  128.         default:
  129.             break;
  130.     }
  131.     return FALSE;
  132. }
  133.  
  134. /* ------------ LEFT_BUTTON Message -------------- */
  135. static int LeftButtonMsg(WINDOW wnd, PARAM p1, PARAM p2)
  136. {
  137.     int mx = (int) p1 - GetLeft(wnd);
  138.     int my = (int) p2 - GetTop(wnd);
  139.     if (TestAttribute(wnd, VSCROLLBAR) &&
  140.                         mx == WindowWidth(wnd)-1)    {
  141.         /* -------- in the right border ------- */
  142.         if (my == 0 || my == ClientHeight(wnd)+1)
  143.             /* --- above or below the scroll bar --- */
  144.             return FALSE;
  145.         if (my == 1)
  146.             /* -------- top scroll button --------- */
  147.             return SendMessage(wnd, SCROLL, FALSE, 0);
  148.         if (my == ClientHeight(wnd))
  149.             /* -------- bottom scroll button --------- */
  150.             return SendMessage(wnd, SCROLL, TRUE, 0);
  151.         /* ---------- in the scroll bar ----------- */
  152.         if (!VSliding && my-1 == wnd->VScrollBox)    {
  153.             RECT rc;
  154.             VSliding = TRUE;
  155.             rc.lf = rc.rt = GetRight(wnd);
  156.             rc.tp = GetTop(wnd)+2;
  157.             rc.bt = GetBottom(wnd)-2;
  158.             return SendMessage(NULL, MOUSE_TRAVEL,
  159.                 (PARAM) &rc, 0);
  160.         }
  161.         if (my-1 < wnd->VScrollBox)
  162.             return SendMessage(wnd,SCROLLPAGE,FALSE,0);
  163.         if (my-1 > wnd->VScrollBox)
  164.             return SendMessage(wnd,SCROLLPAGE,TRUE,0);
  165.     }
  166.     if (TestAttribute(wnd, HSCROLLBAR) &&
  167.                         my == WindowHeight(wnd)-1) {
  168.         /* -------- in the bottom border ------- */
  169.         if (mx == 0 || my == ClientWidth(wnd)+1)
  170.             /* ------  outside the scroll bar ---- */
  171.             return FALSE;
  172.         if (mx == 1)
  173.             return SendMessage(wnd, HORIZSCROLL,FALSE,0);
  174.         if (mx == WindowWidth(wnd)-2)
  175.             return SendMessage(wnd, HORIZSCROLL,TRUE,0);
  176.         if (!HSliding && mx-1 == wnd->HScrollBox)    {
  177.             /* --- hit the scroll box --- */
  178.             RECT rc;
  179.             rc.lf = GetLeft(wnd)+2;
  180.             rc.rt = GetRight(wnd)-2;
  181.             rc.tp = rc.bt = GetBottom(wnd);
  182.             /* - keep the mouse in the scroll bar - */
  183.             SendMessage(NULL,MOUSE_TRAVEL,(PARAM)&rc,0);
  184.             HSliding = TRUE;
  185.             return TRUE;
  186.         }
  187.         if (mx-1 < wnd->HScrollBox)
  188.             return SendMessage(wnd,HORIZPAGE,FALSE,0);
  189.         if (mx-1 > wnd->HScrollBox)
  190.             return SendMessage(wnd,HORIZPAGE,TRUE,0);
  191.     }
  192.     return FALSE;
  193. }
  194.  
  195. /* ------------ MOUSE_MOVED Message -------------- */
  196. static BOOL MouseMovedMsg(WINDOW wnd, PARAM p1, PARAM p2)
  197. {
  198.     int mx = (int) p1 - GetLeft(wnd);
  199.     int my = (int) p2 - GetTop(wnd);
  200.     if (VSliding)    {
  201.         /* ---- dragging the vertical scroll box --- */
  202.         if (my-1 != wnd->VScrollBox)    {
  203.             foreground = FrameForeground(wnd);
  204.             background = FrameBackground(wnd);
  205.             wputch(wnd, SCROLLBARCHAR, WindowWidth(wnd)-1,
  206.                     wnd->VScrollBox+1);
  207.             wnd->VScrollBox = my-1;
  208.             wputch(wnd, SCROLLBOXCHAR, WindowWidth(wnd)-1,
  209.                     my);
  210.         }
  211.         return TRUE;
  212.     }
  213.     if (HSliding)    {
  214.         /* --- dragging the horizontal scroll box --- */
  215.         if (mx-1 != wnd->HScrollBox)    {
  216.             foreground = FrameForeground(wnd);
  217.             background = FrameBackground(wnd);
  218.             wputch(wnd, SCROLLBARCHAR, wnd->HScrollBox+1,
  219.                     WindowHeight(wnd)-1);
  220.             wnd->HScrollBox = mx-1;
  221.             wputch(wnd, SCROLLBOXCHAR, mx, WindowHeight(wnd)-1);
  222.         }
  223.         return TRUE;
  224.     }
  225.     return FALSE;
  226. }
  227.  
  228. /* ------------ BUTTON_RELEASED Message -------------- */
  229. static void ButtonReleasedMsg(WINDOW wnd)
  230. {
  231.     if (HSliding || VSliding)    {
  232.         /* release the mouse ouside the scroll bar */
  233.         SendMessage(NULL, MOUSE_TRAVEL, 0, 0);
  234.         VSliding ? ComputeWindowTop(wnd):ComputeWindowLeft(wnd);
  235.         SendMessage(wnd, PAINT, 0, 0);
  236.         SendMessage(wnd, KEYBOARD_CURSOR, 0, 0);
  237.         VSliding = HSliding = FALSE;
  238.     }
  239. }
  240.  
  241. /* ------------ SCROLL Message -------------- */
  242. static BOOL ScrollMsg(WINDOW wnd, PARAM p1)
  243. {
  244.     /* ---- vertical scroll one line ---- */
  245.     if (p1)    {
  246.         /* ----- scroll one line up ----- */
  247.         if (wnd->wtop+ClientHeight(wnd) >= wnd->wlines)
  248.             return FALSE;
  249.         wnd->wtop++;
  250.     }
  251.     else    {
  252.         /* ----- scroll one line down ----- */
  253.         if (wnd->wtop == 0)
  254.             return FALSE;
  255.         --wnd->wtop;
  256.     }
  257.     if (isVisible(wnd))    {
  258.         RECT rc;
  259.         rc = ClipRectangle(wnd, ClientRect(wnd));
  260.         if (ValidRect(rc))    {
  261.             /* ---- scroll the window ----- */
  262.             if (wnd != inFocus)
  263.                 SendMessage(wnd, PAINT, 0, 0);
  264.             else    {
  265.                 scroll_window(wnd, rc, (int)p1);
  266.                 if (!(int)p1)
  267.                     /* -- write top line (down) -- */
  268.                     WriteTextLine(wnd,NULL,wnd->wtop,FALSE);
  269.                 else    {
  270.                     /* -- write bottom line (up) -- */
  271.                     int y=RectBottom(rc)-GetClientTop(wnd);
  272.                     WriteTextLine(wnd, NULL,
  273.                         wnd->wtop+y, FALSE);
  274.                 }
  275.             }
  276.         }
  277.         /* ---- reset the scroll box ---- */
  278.         if (TestAttribute(wnd, VSCROLLBAR))    {
  279.             int vscrollbox = ComputeVScrollBox(wnd);
  280.             if (vscrollbox != wnd->VScrollBox)
  281.                 MoveScrollBox(wnd, vscrollbox);
  282.         }
  283.     }
  284.     return TRUE;
  285. }
  286.  
  287. /* ------------ HORIZSCROLL Message -------------- */
  288. static BOOL HorizScrollMsg(WINDOW wnd, PARAM p1)
  289. {
  290.     /* --- horizontal scroll one column --- */
  291.     if (p1)    {
  292.         /* --- scroll left --- */
  293.         if (wnd->wleft + ClientWidth(wnd)-1 >= wnd->textwidth)
  294.             return FALSE;
  295.         wnd->wleft++;
  296.     }
  297.     else    {
  298.         /* --- scroll right --- */
  299.         if (wnd->wleft == 0)
  300.             return FALSE;
  301.         --wnd->wleft;
  302.     }
  303.     SendMessage(wnd, PAINT, 0, 0);
  304.     return TRUE;
  305. }
  306.  
  307. /* ------------  SCROLLPAGE Message -------------- */
  308. static void ScrollPageMsg(WINDOW wnd, PARAM p1)
  309. {
  310.     /* --- vertical scroll one page --- */
  311.     if ((int) p1 == FALSE)    {
  312.         /* ---- page up ---- */
  313.         if (wnd->wtop)
  314.             wnd->wtop -= ClientHeight(wnd);
  315.     }
  316.     else     {
  317.         /* ---- page down ---- */
  318.         if (wnd->wtop+ClientHeight(wnd) < wnd->wlines) {
  319.             wnd->wtop += ClientHeight(wnd);
  320.             if (wnd->wtop>wnd->wlines-ClientHeight(wnd))
  321.                 wnd->wtop=wnd->wlines-ClientHeight(wnd);
  322.         }
  323.     }
  324.     if (wnd->wtop < 0)
  325.         wnd->wtop = 0;
  326.     SendMessage(wnd, PAINT, 0, 0);
  327. }
  328.  
  329. /* ------------ HORIZSCROLLPAGE Message -------------- */
  330. static void HorizScrollPageMsg(WINDOW wnd, PARAM p1)
  331. {
  332.     /* --- horizontal scroll one page --- */
  333.     if ((int) p1 == FALSE)
  334.         /* ---- page left ----- */
  335.         wnd->wleft -= ClientWidth(wnd);
  336.     else    {
  337.         /* ---- page right ----- */
  338.         wnd->wleft += ClientWidth(wnd);
  339.         if (wnd->wleft > wnd->textwidth-ClientWidth(wnd))
  340.             wnd->wleft = wnd->textwidth-ClientWidth(wnd);
  341.     }
  342.     if (wnd->wleft < 0)
  343.         wnd->wleft = 0;
  344.     SendMessage(wnd, PAINT, 0, 0);
  345. }
  346.  
  347. /* ------------ SCROLLDOC Message -------------- */
  348. static void ScrollDocMsg(WINDOW wnd, PARAM p1)
  349. {
  350.     /* --- scroll to beginning or end of document --- */
  351.     if ((int) p1)
  352.         wnd->wtop = wnd->wleft = 0;
  353.     else if (wnd->wtop+ClientHeight(wnd) < wnd->wlines){
  354.         wnd->wtop = wnd->wlines-ClientHeight(wnd);
  355.         wnd->wleft = 0;
  356.     }
  357.     SendMessage(wnd, PAINT, 0, 0);
  358. }
  359.  
  360. /* ------------ PAINT Message -------------- */
  361. static void PaintMsg(WINDOW wnd, PARAM p1, PARAM p2)
  362. {
  363.     /* ------ paint the client area ----- */
  364.     RECT rc, rcc;
  365.     int y;
  366.     char blankline[201];
  367.  
  368.     /* ----- build the rectangle to paint ----- */
  369.     if ((RECT *)p1 == NULL)
  370.         rc=RelativeWindowRect(wnd, WindowRect(wnd));
  371.     else
  372.         rc= *(RECT *)p1;
  373.     if (TestAttribute(wnd, HASBORDER) &&
  374.             RectRight(rc) >= WindowWidth(wnd)-1) {
  375.         if (RectLeft(rc) >= WindowWidth(wnd)-1)
  376.             return;
  377.         RectRight(rc) = WindowWidth(wnd)-2;
  378.     }
  379.     rcc = AdjustRectangle(wnd, rc);
  380.  
  381.     if (!p2 && wnd != inFocus)
  382.         ClipString++;
  383.  
  384.     /* ----- blank line for padding ----- */
  385.     memset(blankline, ' ', SCREENWIDTH);
  386.     blankline[RectRight(rcc)+1] = '\0';
  387.  
  388.     /* ------- each line within rectangle ------ */
  389.     for (y = RectTop(rc); y <= RectBottom(rc); y++){
  390.         int yy;
  391.         /* ---- test outside of Client area ---- */
  392.         if (TestAttribute(wnd,
  393.                     HASBORDER | HASTITLEBAR))    {
  394.             if (y < TopBorderAdj(wnd))
  395.                 continue;
  396.             if (y > WindowHeight(wnd)-2)
  397.                 continue;
  398.         }
  399.         yy = y-TopBorderAdj(wnd);
  400.         if (yy < wnd->wlines-wnd->wtop)
  401.             /* ---- paint a text line ---- */
  402.             WriteTextLine(wnd, &rc,
  403.                         yy+wnd->wtop, FALSE);
  404.         else    {
  405.             /* ---- paint a blank line ---- */
  406.             SetStandardColor(wnd);
  407.             writeline(wnd, blankline+RectLeft(rcc),
  408.                     RectLeft(rcc)+1, y, FALSE);
  409.         }
  410.     }
  411.     /* ------- position the scroll box ------- */
  412.     if (TestAttribute(wnd, VSCROLLBAR|HSCROLLBAR)) {
  413.         int hscrollbox = ComputeHScrollBox(wnd);
  414.         int vscrollbox = ComputeVScrollBox(wnd);
  415.         if (hscrollbox != wnd->HScrollBox ||
  416.                 vscrollbox != wnd->VScrollBox)    {
  417.             wnd->HScrollBox = hscrollbox;
  418.             wnd->VScrollBox = vscrollbox;
  419.             SendMessage(wnd, BORDER, p1, 0);
  420.         }
  421.     }
  422.     if (!p2 && wnd != inFocus)
  423.         --ClipString;
  424. }
  425.  
  426. /* ------------ CLOSE_WINDOW Message -------------- */
  427. static void CloseWindowMsg(WINDOW wnd)
  428. {
  429.     SendMessage(wnd, CLEARTEXT, 0, 0);
  430.     if (wnd->TextPointers != NULL)    {
  431.         free(wnd->TextPointers);
  432.         wnd->TextPointers = NULL;
  433.     }
  434. }
  435.  
  436. /* ----------- TEXTBOX Message-processing Module ----------- */
  437. int TextBoxProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  438. {
  439.     switch (msg)    {
  440.         case CREATE_WINDOW:
  441.             wnd->HScrollBox = wnd->VScrollBox = 1;
  442.             ClearTextPointers(wnd);
  443.             break;
  444.         case ADDTEXT:
  445.             return AddTextMsg(wnd, (char *) p1);
  446.         case DELETETEXT:
  447.             DeleteTextMsg(wnd, (int) p1);
  448.             return TRUE;
  449.         case INSERTTEXT:
  450.             InsertTextMsg(wnd, (char *) p1, (int) p2);
  451.             return TRUE;
  452.         case SETTEXT:
  453.             return SetTextMsg(wnd, (char *) p1);
  454.         case CLEARTEXT:
  455.             ClearTextMsg(wnd);
  456.             break;
  457.         case KEYBOARD:
  458.             if (WindowMoving || WindowSizing)
  459.                 break;
  460.             if (KeyboardMsg(wnd, p1))
  461.                 return TRUE;
  462.             break;
  463.         case LEFT_BUTTON:
  464.             if (WindowSizing || WindowMoving)
  465.                 return FALSE;
  466.             if (LeftButtonMsg(wnd, p1, p2))
  467.                 return TRUE;
  468.             break;
  469.         case MOUSE_MOVED:
  470.             if (MouseMovedMsg(wnd, p1, p2))
  471.                 return TRUE;
  472.             break;
  473.         case BUTTON_RELEASED:
  474.             ButtonReleasedMsg(wnd);
  475.             break;
  476.         case SCROLL:
  477.             return ScrollMsg(wnd, p1);
  478.         case HORIZSCROLL:
  479.             return HorizScrollMsg(wnd, p1);
  480.         case SCROLLPAGE:
  481.             ScrollPageMsg(wnd, p1);
  482.             return TRUE;
  483.         case HORIZPAGE:
  484.             HorizScrollPageMsg(wnd, p1);
  485.             return TRUE;
  486.         case SCROLLDOC:
  487.             ScrollDocMsg(wnd, p1);
  488.             return TRUE;
  489.         case PAINT:
  490.             if (isVisible(wnd) && wnd->wlines)    {
  491.                 PaintMsg(wnd, p1, p2);
  492.                 return FALSE;
  493.             }
  494.             break;
  495.         case CLOSE_WINDOW:
  496.             CloseWindowMsg(wnd);
  497.             break;
  498.         default:
  499.             break;
  500.     }
  501.     return BaseWndProc(TEXTBOX, wnd, msg, p1, p2);
  502. }
  503.  
  504. /* ------ compute the vertical scroll box position from
  505.                    the text pointers --------- */
  506. static int ComputeVScrollBox(WINDOW wnd)
  507. {
  508.     int pagelen = wnd->wlines - ClientHeight(wnd);
  509.     int barlen = ClientHeight(wnd)-2;
  510.     int lines_tick;
  511.     int vscrollbox;
  512.  
  513.     if (pagelen < 1 || barlen < 1)
  514.         vscrollbox = 1;
  515.     else    {
  516.         if (pagelen > barlen)
  517.             lines_tick = pagelen / barlen;
  518.         else
  519.             lines_tick = barlen / pagelen;
  520.         vscrollbox = 1 + (wnd->wtop / lines_tick);
  521.         if (vscrollbox > ClientHeight(wnd)-2 ||
  522.                 wnd->wtop + ClientHeight(wnd) >= wnd->wlines)
  523.             vscrollbox = ClientHeight(wnd)-2;
  524.     }
  525.     return vscrollbox;
  526. }
  527.  
  528. /* ---- compute top text line from scroll box position ---- */
  529. static void ComputeWindowTop(WINDOW wnd)
  530. {
  531.     int pagelen = wnd->wlines - ClientHeight(wnd);
  532.     if (wnd->VScrollBox == 0)
  533.         wnd->wtop = 0;
  534.     else if (wnd->VScrollBox == ClientHeight(wnd)-2)
  535.         wnd->wtop = pagelen;
  536.     else    {
  537.         int barlen = ClientHeight(wnd)-2;
  538.         int lines_tick;
  539.  
  540.         if (pagelen > barlen)
  541.             lines_tick = pagelen / barlen;
  542.         else
  543.             lines_tick = barlen / pagelen;
  544.         wnd->wtop = (wnd->VScrollBox-1) * lines_tick;
  545.         if (wnd->wtop + ClientHeight(wnd) > wnd->wlines)
  546.             wnd->wtop = pagelen;
  547.     }
  548.     if (wnd->wtop < 0)
  549.         wnd->wtop = 0;
  550. }
  551.  
  552. /* ------ compute the horizontal scroll box position from
  553.                    the text pointers --------- */
  554. static int ComputeHScrollBox(WINDOW wnd)
  555. {
  556.     int pagewidth = wnd->textwidth - ClientWidth(wnd);
  557.     int barlen = ClientWidth(wnd)-2;
  558.     int chars_tick;
  559.     int hscrollbox;
  560.  
  561.     if (pagewidth < 1 || barlen < 1)
  562.         hscrollbox = 1;
  563.     else     {
  564.         if (pagewidth > barlen)
  565.             chars_tick = pagewidth / barlen;
  566.         else
  567.             chars_tick = barlen / pagewidth;
  568.         hscrollbox = 1 + (wnd->wleft / chars_tick);
  569.         if (hscrollbox > ClientWidth(wnd)-2 ||
  570.                 wnd->wleft + ClientWidth(wnd) >= wnd->textwidth)
  571.             hscrollbox = ClientWidth(wnd)-2;
  572.     }
  573.     return hscrollbox;
  574. }
  575.  
  576. /* ---- compute left column from scroll box position ---- */
  577. static void ComputeWindowLeft(WINDOW wnd)
  578. {
  579.     int pagewidth = wnd->textwidth - ClientWidth(wnd);
  580.  
  581.     if (wnd->HScrollBox == 0)
  582.         wnd->wleft = 0;
  583.     else if (wnd->HScrollBox == ClientWidth(wnd)-2)
  584.         wnd->wleft = pagewidth;
  585.     else    {
  586.         int barlen = ClientWidth(wnd)-2;
  587.         int chars_tick;
  588.  
  589.         if (pagewidth > barlen)
  590.             chars_tick = pagewidth / barlen;
  591.         else
  592.             chars_tick = barlen / pagewidth;
  593.         wnd->wleft = (wnd->HScrollBox-1) * chars_tick;
  594.         if (wnd->wleft + ClientWidth(wnd) > wnd->textwidth)
  595.             wnd->wleft = pagewidth;
  596.     }
  597.     if (wnd->wleft < 0)
  598.         wnd->wleft = 0;
  599. }
  600.  
  601. /* ----- get the text to a specified line ----- */
  602. static char *GetTextLine(WINDOW wnd, int selection)
  603. {
  604.     char *line;
  605.     int len = 0;
  606.     char *cp, *cp1;
  607.     cp = cp1 = TextLine(wnd, selection);
  608.     while (*cp && *cp != '\n')    {
  609.         len++;
  610.         cp++;
  611.     }
  612.     line = malloc(len+6);
  613.     if (line != NULL)    {
  614.         memmove(line, cp1, len);
  615.         line[len] = '\0';
  616.     }
  617.     return line;
  618. }
  619.  
  620. /* ------- write a line of text to a textbox window ------- */
  621. void WriteTextLine(WINDOW wnd, RECT *rcc, int y, BOOL reverse)
  622. {
  623.     int len = 0;
  624.     int dif = 0;
  625.     unsigned char line[200];
  626.     RECT rc;
  627.     unsigned char *lp, *svlp;
  628.     int lnlen;
  629.     int i;
  630.     BOOL trunc = FALSE;
  631.  
  632.     /* ------ make sure y is inside the window ----- */
  633.     if (y < wnd->wtop || y >= wnd->wtop+ClientHeight(wnd))
  634.         return;
  635.  
  636.     /* ---- build the retangle within which can write ---- */
  637.     if (rcc == NULL)    {
  638.         rc = RelativeWindowRect(wnd, WindowRect(wnd));
  639.         if (TestAttribute(wnd, HASBORDER) &&
  640.                 RectRight(rc) >= WindowWidth(wnd)-1)
  641.             RectRight(rc) = WindowWidth(wnd)-2;
  642.     }
  643.     else
  644.         rc = *rcc;
  645.  
  646.     /* ----- make sure rectangle is within window ------ */
  647.     if (RectLeft(rc) >= WindowWidth(wnd)-1)
  648.         return;
  649.     if (RectRight(rc) == 0)
  650.         return;
  651.     rc = AdjustRectangle(wnd, rc);
  652.     if (y-wnd->wtop<RectTop(rc) || y-wnd->wtop>RectBottom(rc))
  653.         return;
  654.  
  655.     /* --- get the text and length of the text line --- */
  656.     lp = svlp = GetTextLine(wnd, y);
  657.     if (svlp == NULL)
  658.         return;
  659.     lnlen = LineLength(lp);
  660.  
  661.     /* -------- insert block color change controls ------- */
  662.     if (TextBlockMarked(wnd))    {
  663.         int bbl = wnd->BlkBegLine;
  664.         int bel = wnd->BlkEndLine;
  665.         int bbc = wnd->BlkBegCol;
  666.         int bec = wnd->BlkEndCol;
  667.         int by = y;
  668.  
  669.         /* ----- put lowest marker first ----- */
  670.         if (bbl > bel)    {
  671.             swap(bbl, bel);
  672.             swap(bbc, bec);
  673.         }
  674.         if (bbl == bel && bbc > bec)
  675.             swap(bbc, bec);
  676.  
  677.         if (by >= bbl && by <= bel)    {
  678.             /* ------ the block includes this line ----- */
  679.             int blkbeg = 0;
  680.             int blkend = lnlen;
  681.             if (!(by > bbl && by < bel))    {
  682.                 /* --- the entire line is not in the block -- */
  683.                 if (by == bbl)
  684.                     /* ---- the block begins on this line --- */
  685.                     blkbeg = bbc;
  686.                 if (by == bel)
  687.                     /* ---- the block ends on this line ---- */
  688.                     blkend = bec;
  689.             }
  690.             /* ----- insert the reset color token ----- */
  691.             memmove(lp+blkend+1,lp+blkend,strlen(lp+blkend)+1);
  692.             lp[blkend] = RESETCOLOR;
  693.             /* ----- insert the change color token ----- */
  694.             memmove(lp+blkbeg+3,lp+blkbeg,strlen(lp+blkbeg)+1);
  695.             lp[blkbeg] = CHANGECOLOR;
  696.             /* ----- insert the color tokens ----- */
  697.             SetReverseColor(wnd);
  698.             lp[blkbeg+1] = foreground | 0x80;
  699.             lp[blkbeg+2] = background | 0x80;
  700.             lnlen += 4;
  701.         }
  702.     }
  703.     /* - make sure left margin doesn't overlap color change - */
  704.     for (i = 0; i < wnd->wleft+3; i++)    {
  705.         if (*(lp+i) == '\0')
  706.             break;
  707.         if (*(unsigned char *)(lp + i) == RESETCOLOR)
  708.             break;
  709.     }
  710.     if (*(lp+i) && i < wnd->wleft+3)    {
  711.         if (wnd->wleft+4 > lnlen)
  712.             trunc = TRUE;
  713.         else 
  714.             lp += 4;
  715.     }
  716.     else     {
  717.         /* --- it does, shift the color change over --- */
  718.         for (i = 0; i < wnd->wleft; i++)    {
  719.             if (*(lp+i) == '\0')
  720.                 break;
  721.             if (*(unsigned char *)(lp + i) == CHANGECOLOR)    {
  722.                 *(lp+wnd->wleft+2) = *(lp+i+2);
  723.                 *(lp+wnd->wleft+1) = *(lp+i+1);
  724.                 *(lp+wnd->wleft) = *(lp+i);
  725.                 break;
  726.             }
  727.         }
  728.     }
  729.     /* ------ build the line to display -------- */
  730.     if (!trunc)    {
  731.         if (lnlen < wnd->wleft)
  732.             lnlen = 0;
  733.         else
  734.             lp += wnd->wleft;
  735.         if (lnlen > RectLeft(rc))    {
  736.             /* ---- the line exceeds the rectangle ---- */
  737.             int ct = RectLeft(rc);
  738.             char *initlp = lp;
  739.             /* --- point to end of clipped line --- */
  740.             while (ct)    {
  741.                 if (*(unsigned char *)lp == CHANGECOLOR)
  742.                     lp += 3;
  743.                 else if (*(unsigned char *)lp == RESETCOLOR)
  744.                     lp++;
  745.                 else
  746.                     lp++, --ct;
  747.             }
  748.             if (RectLeft(rc))    {
  749.                 char *lpp = lp;
  750.                 while (*lpp)    {
  751.                     if (*(unsigned char*)lpp==CHANGECOLOR)
  752.                         break;
  753.                     if (*(unsigned char*)lpp==RESETCOLOR) {
  754.                         lpp = lp;
  755.                         while (lpp >= initlp)    {
  756.                             if (*(unsigned char *)lpp ==
  757.                                             CHANGECOLOR) {
  758.                                 lp -= 3;
  759.                                 memmove(lp,lpp,3);
  760.                                 break;
  761.                             }
  762.                             --lpp;
  763.                         }
  764.                         break;
  765.                     }
  766.                     lpp++;
  767.                 }
  768.             }
  769.             lnlen = LineLength(lp);
  770.             len = min(lnlen, RectWidth(rc));
  771.             dif = strlen(lp) - lnlen;
  772.             len += dif;
  773.             if (len > 0)
  774.                 strncpy(line, lp, len);
  775.         }
  776.     }
  777.     /* -------- pad the line --------- */
  778.     while (len < RectWidth(rc)+dif)
  779.         line[len++] = ' ';
  780.     line[len] = '\0';
  781.     dif = 0;
  782.     /* ------ establish the line's main color ----- */
  783.     if (reverse)    {
  784.         char *cp = line;
  785.         SetReverseColor(wnd);
  786.         while ((cp = strchr(cp, CHANGECOLOR)) != NULL)    {
  787.             cp += 2;
  788.             *cp++ = background | 0x80;
  789.         }
  790.         if (*(unsigned char *)line == CHANGECOLOR)
  791.             dif = 3;
  792.     }
  793.     else
  794.         SetStandardColor(wnd);
  795.     /* ------- display the line -------- */
  796.     writeline(wnd, line+dif,
  797.                 RectLeft(rc)+BorderAdj(wnd),
  798.                     y-wnd->wtop+TopBorderAdj(wnd), FALSE);
  799.     free(svlp);
  800. }
  801.  
  802. /* ----- set anchor point for marking text block ----- */
  803. void SetAnchor(WINDOW wnd, int mx, int my)
  804. {
  805.     if (TextBlockMarked(wnd))    {
  806.         ClearTextBlock(wnd);
  807.         SendMessage(wnd, PAINT, 0, 0);
  808.     }
  809.     /* ------ set the anchor ------ */
  810.     wnd->BlkBegLine = wnd->BlkEndLine = my;
  811.     wnd->BlkBegCol = wnd->BlkEndCol = mx;
  812. }
  813.  
  814. void MarkTextBlock(WINDOW wnd, int BegLine, int BegCol,
  815.                                int EndLine, int EndCol)
  816. {
  817.     wnd->BlkBegLine = BegLine;
  818.     wnd->BlkEndLine = EndLine;
  819.     wnd->BlkBegCol = BegCol;
  820.     wnd->BlkEndCol = EndCol;
  821. }
  822.  
  823. /* ----- clear and initialize text line pointer array ----- */
  824. void ClearTextPointers(WINDOW wnd)
  825. {
  826.     wnd->TextPointers = realloc(wnd->TextPointers, sizeof(int));
  827.     if (wnd->TextPointers != NULL)
  828.         *(wnd->TextPointers) = 0;
  829. }
  830.  
  831. #define INITLINES 100
  832.  
  833. /* ---- build array of pointers to text lines ---- */
  834. void BuildTextPointers(WINDOW wnd)
  835. {
  836.     char *cp = wnd->text, *cp1;
  837.     int incrs = INITLINES;
  838.     unsigned int off;
  839.     wnd->textwidth = wnd->wlines = 0;
  840.     while (*cp)    {
  841.         if (incrs == INITLINES)    {
  842.             incrs = 0;
  843.             wnd->TextPointers = realloc(wnd->TextPointers,
  844.                     (wnd->wlines + INITLINES) * sizeof(int));
  845.             if (wnd->TextPointers == NULL)
  846.                 break;
  847.         }
  848.         off = (unsigned int) (cp - wnd->text);
  849.         *((wnd->TextPointers) + wnd->wlines) = off;
  850.         wnd->wlines++;
  851.         incrs++;
  852.         cp1 = cp;
  853.         while (*cp && *cp != '\n')
  854.             cp++;
  855.         wnd->textwidth = max(wnd->textwidth,
  856.                         (unsigned int) (cp - cp1));
  857.         if (*cp)
  858.             cp++;
  859.     }
  860. }
  861.  
  862. static void MoveScrollBox(WINDOW wnd, int vscrollbox)
  863. {
  864.     foreground = FrameForeground(wnd);
  865.     background = FrameBackground(wnd);
  866.     wputch(wnd, SCROLLBARCHAR, WindowWidth(wnd)-1,
  867.             wnd->VScrollBox+1);
  868.     wputch(wnd, SCROLLBOXCHAR, WindowWidth(wnd)-1,
  869.             vscrollbox+1);
  870.     wnd->VScrollBox = vscrollbox;
  871. }
  872.  
  873. int TextLineNumber(WINDOW wnd, char *lp)
  874. {
  875.     int lineno;
  876.     char *cp;
  877.     for (lineno = 0; lineno < wnd->wlines; lineno++)    {
  878.         cp = wnd->text + *((wnd->TextPointers) + lineno);
  879.         if (cp == lp)
  880.             return lineno;
  881.         if (cp > lp)
  882.             break;
  883.     }
  884.     return lineno-1;
  885. }
  886.  
  887.  
  888.